#include "QSim.h"

QSim::QSim(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle("QSim");

    setGeometry(100,100,800,800);

    mMainWidget = new QWidget(this);
    mMainWidget->setGeometry(0,0,800,800);

    mLogLabel = new QLabel(mMainWidget);
    mLogLabel->setText("Log View");
    mLogLabel->setGeometry(10,30,70,50);
    mPushButtonForLogClear = new QPushButton(mMainWidget);
    mPushButtonForLogClear->setText("Log Clear");
    mPushButtonForLogClear->setGeometry(80,45,100,20);
    mLogText = new QTextEdit(mMainWidget);
    mLogText->setGeometry(10,70,400,730);

    mLabelForComboboxLabel = new QLabel(mMainWidget);
    mLabelForComboboxLabel->setText("CPU:");
    mLabelForComboboxLabel->setGeometry(10,0,30,50);

    createComboBoxForSelectCPU();

    mLineEditForClock = new QLineEdit(mMainWidget);
    mLineEditForClock->setGeometry(110,15,80,25);
    mLineEditForClock->setAlignment(Qt::AlignRight);
    mLabelForClock = new QLabel(mMainWidget);
    mLabelForClock->setText("Hz");
    mLabelForClock->setGeometry(195,15,30,30);

    mPushButtonForCreateCPU = new QPushButton(mMainWidget);
    mPushButtonForCreateCPU->setText("CPU CREATE");
    mPushButtonForCreateCPU->setGeometry(220,10,180,50);

    createMemorySelectRadioGroup();

    mPushButtonForLoadHex = new QPushButton(mMainWidget);
    mPushButtonForLoadHex->setText("LoadHex");
    mPushButtonForLoadHex->setGeometry(560,10,100,50);

    mPushButtonForCPUstart = new QPushButton(mMainWidget);
    mPushButtonForCPUstart->setText("CPU START");
    mPushButtonForCPUstart->setGeometry(665,10,100,50);

    createLCDall();

    connect(mPushButtonForCreateCPU,SIGNAL(clicked()),this,SLOT(createCPU()));
    connect(mPushButtonForLogClear,SIGNAL(clicked()),this,SLOT(clearLog()));
    connect(mPushButtonForLoadHex,SIGNAL(clicked()),this,SLOT(openFileDialog()));
    connect(mPushButtonForCPUstart,SIGNAL(clicked()),this,SLOT(startCPU()));
}

QSim::~QSim()
{
    
}


void QSim::writeLog(QString& str){
    if(mLogText != NULL){
        mLogText->append(str);
        str.clear();
    }
}

void QSim::clearLog(){
    if(mLogText != NULL){
        mLogText->clear();
    }
}

void QSim::createComboBoxForSelectCPU()
{
    mComboBoxForSelectCPU = new QComboBox(mMainWidget);
    mComboBoxForSelectCPU->addItem("8051");
    mComboBoxForSelectCPU->addItem("AVR");
    mComboBoxForSelectCPU->addItem("PIC");
    mComboBoxForSelectCPU->addItem("ARM");
    mComboBoxForSelectCPU->setGeometry(50,10,50,30);
}

void QSim::createCPU(){
    if(mCPU != NULL){
        delete &mCPU;
    }

    QString str=mLineEditForClock->text();
    mClock = str.toInt();
    if(mClock == 0){
         mClock = 11059200;

      //  mLineEditForClock->setText(QString("%1").arg(mClock));
         mLineEditForClock->setText(QString("TEST MODE"));
    }

    switch(mComboBoxForSelectCPU->currentIndex()){
    case 0:
        mCPU = new QCPU(QCPU::MCS51,mClock);
        writeLog(mCPU->mLog);
        break;
    case 1:
        break;
    case 2:
        break;
    case 3:
        break;
    }
}

void QSim::createMemorySelectRadioGroup(){
    if(mCPU == NULL){
        return;
    }

    mRadioGroup = new QGroupBox(mMainWidget);

    mRadioMemorySelectInRom = new QRadioButton(mMainWidget);
    mRadioMemorySelectInRom->setText("Inner ROM");
    mRadioMemorySelectExRam = new QRadioButton(mMainWidget);
    mRadioMemorySelectExRam->setText("External RAM");
    mRadioMemorySelectExRom = new QRadioButton(mMainWidget);
    mRadioMemorySelectExRom->setText("External ROM");

    mVLayout = new QVBoxLayout();
    mVLayout->addWidget(mRadioMemorySelectInRom);
    mVLayout->addWidget(mRadioMemorySelectExRam);
    mVLayout->addWidget(mRadioMemorySelectExRom);
    mRadioGroup->setLayout(mVLayout);
    mRadioGroup->setGeometry(420,10,130,80);

}

void QSim::openFileDialog(){

    QString path = QFileDialog::getOpenFileName(this,tr("Select Hex File"),".",tr("Hex File(*.hex)"));
    QFile file(path);
    if(!file.open(QIODevice::ReadOnly)){
        QMessageBox msg;
        msg.setText("Open Error");
        msg.exec();
        return;
    }

    if(mCPU == NULL){
        return;
    }

    //QMemoryDevice *memory = mCPU->getMemoryDeivce(1);
    QByteArray temp = file.readAll();
    mLog.append(temp);
    writeLog(mLog);
    int i;
    int max = temp.length();
    for(i=0;i<max;i++){
        mCPU->mCodeSpace[i] = temp.at(i);
        mLog.append(QString("0x%1").arg(mCPU->mCodeSpace[i],0,16));
       writeLog(mLog);
    }
}

void QSim::startCPU(){
//    QMemoryDevice *memory = mCPU->getMemoryDeivce(1);
   // char tempInstruction = mCPU->mMemorySpace[mCPU->SFR_IP];
    mTimer = new QTimer(this);
   // mTimer->start((1/mClock)*12);
    mTimer->start(2000);
    mClockCycle = 0;
    mLog.append("Start Timer");
    writeLog(mLog);
    connect(mTimer,SIGNAL(timeout()),this,SLOT(clockCycle()));
}

void QSim::clockCycle(){
    mCPU->nextInstruction(mClockCycle);
    mClockCycle++;
    displayLCD();
    writeLog(mCPU->mLog);
}

void QSim::createLCDall(){


    mLabelforACC_LCD = new QLabel(mMainWidget);
    mLabelforACC_LCD->setText("ACC");
    mLabelforACC_LCD->setGeometry(420,90,50,30);

    mACC_LCD = new QLCDNumber(mMainWidget);
    mACC_LCD->setGeometry(420,120,350,80);
    mACC_LCD->setMode(QLCDNumber::Hex);

    mLabelforPC_LCD = new QLabel(mMainWidget);
    mLabelforPC_LCD->setText("PC");
    mLabelforPC_LCD->setGeometry(420,200,50,30);

    mPC_LCD = new QLCDNumber(mMainWidget);
    mPC_LCD->setGeometry(420,230,350,80);
    mPC_LCD->setMode(QLCDNumber::Hex);

    mLabelforP0_LCD = new QLabel(mMainWidget);
    mLabelforP0_LCD->setText("CYCLE");
    mLabelforP0_LCD->setGeometry(420,310,50,30);

    mP0_LCD = new QLCDNumber(mMainWidget);
    mP0_LCD->setGeometry(420,340,350,80);
    mP0_LCD->setMode(QLCDNumber::Dec);

    mLabelforP1_LCD = new QLabel(mMainWidget);
    mLabelforP1_LCD->setText("IR");
    mLabelforP1_LCD->setGeometry(420,420,50,30);

    mP1_LCD = new QLCDNumber(mMainWidget);
    mP1_LCD->setGeometry(420,450,350,80);
    mP1_LCD->setMode(QLCDNumber::Hex);

    mLabelforP2_LCD = new QLabel(mMainWidget);
    mLabelforP2_LCD->setText("SP");
    mLabelforP2_LCD->setGeometry(420,530,50,30);

    mP2_LCD = new QLCDNumber(mMainWidget);
    mP2_LCD->setGeometry(420,580,350,80);
    mP2_LCD->setMode(QLCDNumber::Hex);

    mLabelforP3_LCD = new QLabel(mMainWidget);
    mLabelforP3_LCD->setText("PSW");
    mLabelforP3_LCD->setGeometry(420,660,50,30);

    mP3_LCD = new QLCDNumber(mMainWidget);
    mP3_LCD->setGeometry(420,690,350,80);
    mP3_LCD->setMode(QLCDNumber::Hex);

}

void QSim::displayLCD(){
    mACC_LCD->display(mCPU->mDataSpace[QCPU::ACC]);
    mPC_LCD->display(mCPU->PC);
    mP0_LCD->display(mClockCycle);
    mP1_LCD->display(mCPU->IR);
    mP2_LCD->display(mCPU->mDataSpace[QCPU::SP]);
    mP3_LCD->display(mCPU->mDataSpace[QCPU::PSW]);
}
